﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using FXnaEngine.Graphics;

using FXnaEngine.Components;

using FXnaEngine.Interfaces;




namespace FXnaEngine
{
   public class FScene
    {
        private FGame game;

        protected FGame Game
        {
            get { return game; }
            
        }


         /// <summary>
        /// Default constructor
        /// </summary>
        public FScene(FGame game)
        {
            this.game = game;



            //初始化自身

            this.InitializeCore();






          
        }




        /// <summary>
        /// A list of all the entities in this scene.
        /// </summary>
        public Dictionary<Guid, FEntity> Entities
        {
            get { return entities; }
        }
        private Dictionary<Guid, FEntity> entities;
        private List<FEntity> entitiesToRemove;



        public int NumberOfActiveEntities
        {
            get { return this.activeEntities.Count; }
        }
        private HashSet<FEntity> activeEntities;
        private List<FEntity> activeEntitiesToAdd;
        private List<FEntity> activeEntitiesToRemove;





        FEntity _rootEntity;


       /// <summary>
       /// 定义的根不允许删除和重置，作为一切管理的核心
       /// </summary>
        public FEntity RootEntity
        {
            get { return _rootEntity; }
           
        }






        #region 更新机制代码

        public  virtual void InitializeCore()
        {
            

          
            this.entities = new Dictionary<Guid, FEntity>();
            this.entitiesToRemove = new List<FEntity>();

            this.activeEntities = new HashSet<FEntity>();
            this.activeEntitiesToAdd = new List<FEntity>();
            this.activeEntitiesToRemove = new List<FEntity>();


        }


        public virtual void LoadContent()
        {

            //根节点相机系统


            this._rootEntity = new FEntity(game);


            //测试而特别输入的

            this._rootEntity.Transform.Position = new Vector3(5, 5, 5);

            this._rootEntity.Transform.LookAt(new Vector3(0, 0, 0));



            //为根节点加入系统相机，以及控制逻辑


           

            this.AddEntity(this._rootEntity);

            FCameraComponent cm = new FCameraComponent(this._rootEntity);
            cm.AspectRatio = (float)this.game.GraphicsDevice.Viewport.Width / (float)this.game.GraphicsDevice.Viewport.Height;


            //FArcBallCameraInputComponent fbc = new FArcBallCameraInputComponent(this._rootEntity);
   
            //先从简单的写起吧

            FEditorInputComponent fec = new FEditorInputComponent(this._rootEntity);





            //这里开始测试自由相机输入模式

            //FFreeCameraComponent free = new FFreeCameraComponent(this._rootEntity);

            





            //试着加入天空盒子,高不清楚 为什么总是反的


            //FEntity sky = new FEntity(this.game);

            //sky.Transform.Rotation=new Vector3 (-90,0,0);


            //FSkyboxComponent fbox = new FSkyboxComponent(sky);


            //this.AddEntity(sky);





            //开始测试渲染系统的模块能力

            Model m=  this.game.Content.Load<Model>("Models/ship1");

            FEntity f = new FEntity(this.game);

            f.Transform.Position = new Vector3(0,0,50);
         
            f.Transform.Scale = new Vector3(0.1f,0.1f,0.1f);



            //FSkinnedMeshRendererComponent fs = new FSkinnedMeshRendererComponent(f, m);

            FModelRendererComponent frc = new FModelRendererComponent(f);

            frc.Model = new FLoadedModel(m);





            this.AddEntity(f);



          


         





            //测试第二个加入

            FEntity f2 = new FEntity(this.game);
            f2.Transform.Position = new Vector3(0, 0, 35);
            f2.Transform.Scale = new Vector3(0.5f,0.5f,0.5f);


            FModelRendererComponent mren = new FModelRendererComponent(f2);

            FRoadModel road = new FRoadModel();
            road.RoadMaterial.Texture = this.game.Content.Load<Texture2D>("Images/road");


            mren.Model = road;






            //FMeshRendererComponent fc2 = new FMeshRendererComponent(f2);
            //fc2.Material.Specular = Vector4.One;

            ////测试在代码


            //Track track = new Track();


            //fc2.Material.Texture = this.game.Content.Load<Texture2D>("Images/road");


            //fc2.Mesh = track.InnerMesh;


            this.AddEntity(f2);




            //测试第三个加入

            FEntity f3 = new FEntity(this.game);

           // f3.Transform.Position = new Vector3(-12.6f, -1, 12.6f);

            f3.Transform.Position = new Vector3(-126f, -50f,-126);

            //f3.Transform.Scale = new Vector3(0.1f,0.1f,0.1f);


           

            FTerrainComponent tc = new FTerrainComponent(f3);


            //测试用

            FTerrain terrain = new FTerrain(257,257);

            tc.Terrain = terrain;



            tc.Material.Texture = FEngineState.Content.Load<Texture2D>("Images/terrain");









            this.AddEntity(f3);





            //该在哪里计算和更新，视图的最大区域呢?，我们先在这里进行尝试，并初始化相机

           


            List<FRendererComponent> list = new List<FRendererComponent>();

            this.GetRendererComponents(ref list);

            if (list.Count>0)
            {
                BoundingSphere bound = list[0].BoundingSphere;

                for (int i = 1; i < list.Count; i++)
                {

                    bound = BoundingSphere.CreateMerged(bound, list[i].BoundingSphere);
                }




                //设置默认相机远近

                //cm 

                fec.TargetPosition = bound.Center;


                //这里我们暂时以物体最大宽度的2倍作为默认观察点位置

                fec.ZoomMax = bound.Radius*2;
              

                
            }

          


            // Set a new render camera
            //发送对应的相机消息，
            //这一句可以先不加


            //MsgSetRenderEntity camSetRenderMsg = ObjectPool.Aquire<MsgSetRenderEntity>();
            //camSetRenderMsg.Entity = this._rootEntity;
            //this.Game.SendInterfaceMessage(camSetRenderMsg, InterfaceType.Camera);




        }

        public virtual void UpdateCore(GameTime gameTime)
        {
            //更新队列信息
            this.ProcessEntityQueues();


            this._rootEntity.Update(gameTime);

            //跟心所有的实体

            foreach (FEntity entity in this.activeEntities)
            {
                entity.Update(gameTime);
            }


        
        }

        #endregion


        #region 对外使用接口功能

     


        public void GetRendererComponents(ref List<FRendererComponent> list)
        {

            foreach (FEntity item in this.activeEntities)
            {
                FRendererComponent f = item.GetRendererComponent();

                if (f!=null)
                {
                    list.Add(f);
                    
                }

            }
 
        }



        #endregion


        /// <summary>
        /// Adds an entity to the overall scene.
        /// </summary>
        /// <param name="inEntity">Entity to add to scene</param>        
        public void AddEntity(FEntity entity)
        {
            this.entities.Add(entity.Guid, entity);


            this.activeEntities.Add(entity);

            //this.activeEntitiesToAdd.Add(entity);


         
        }


        /// <summary>
        /// Removes an entity from the overall scene on the next Update() loop.
        /// </summary>
        /// <param name="targetEntity">Entity to remove from scene</param>        
        private void AddEntityToDeleteQueue(FEntity entity)
        {
            this.entitiesToRemove.Add(entity);
            this.activeEntitiesToAdd.Remove(entity);
            this.activeEntitiesToRemove.Add(entity);
        }

    

       

        private void ShutdownEntity(FEntity entity)
        {
            // If entity is in a scene
            if (entity != null)
            {
                // Send a shutdown to the entity
                entity.Shutdown();

                // Shutdown should be complete, now pull it from the scene
                AddEntityToDeleteQueue(entity);
            }
        }

    




        private void ProcessEntityQueues()
        {
            for (int i = 0; i < this.entitiesToRemove.Count; ++i)
            {
                this.entities.Remove(this.entitiesToRemove[i].Guid);
            }
            this.entitiesToRemove.Clear();

            foreach (FEntity entity in this.activeEntitiesToAdd)
            {
                this.activeEntities.Add(entity);
            }
            this.activeEntitiesToAdd.Clear();

            foreach (FEntity entity in this.activeEntitiesToRemove)
            {
                this.activeEntities.Remove(entity);
            }
            this.activeEntitiesToRemove.Clear();
        }






    }
}
